#ifndef _DFA_BASE_IMPL
#define _DFA_BASE_IMPL

#include "Dfa_base.h"
using namespace dfa_base;

/* implement dfa_base::
class Dfa_base {
		mylib::Lim_matrix<State_type> *start_tab;
		mylib::Set<State_type> start_acc_state;
		mylib::Lim_matrix<State_type> *entity_tab;
		mylib::Set<State_type> entity_acc_state;
		mylib::Lim_matrix<State_type> *suffix_tab;
		mylib::Set<State_type> suffix_acc_state;
		State_type _start_state;
		bool _start_line;
*/
#include "Dfa_base_loc.h"

Dfa_base::Dfa_base(const State_type *tab, State_type start, bool start_ln) {			// build from data
	State_type acc_num;
	start_tab = entity_tab = suffix_tab = 0;
	try {
		if( (acc_num=*tab) )	{			// exist start automata
			while(acc_num-- > 0 ) {		// get start accepting state
				start_acc_state.insert(*(++tab));
			}
			start_tab = new mylib::Lim_matrix<State_type>((++tab));	// build table
			tab += start_tab->row()*start_tab->col()+3;				// 3 = base + row + col
		} else
			tab++;
		if( (acc_num=*tab) ){	/// exist entity automata
			while( acc_num-- > 0 ) {
				entity_acc_state.insert(*(++tab));
			}
			entity_tab = new mylib::Lim_matrix<State_type>((++tab));	// build table
			tab += entity_tab->row()*entity_tab->col()+3;				// 3 = base + row + col
		} else
			tab++;
		if( (acc_num=*tab)) {
			while( acc_num-- > 0 ) {
				suffix_acc_state.insert(*(++tab));
			}
			suffix_tab = new mylib::Lim_matrix<State_type>(++tab);	// build table
		}
	} catch(...) {
		if( start_tab ) {
			delete start_tab;
			start_tab = 0;
		}
		if( entity_tab ) {
			delete entity_tab;
			entity_tab = 0;
		}
		if( suffix_tab ) {
			delete suffix_tab;
			suffix_tab = 0;
		}
		throw Dfa_base::Out_of_mem();
	}
	_start_state=start;
	_start_line = start_ln;
}
#include "Build_dfa_tree.h"
Dfa_base::Dfa_base(mylib::Buffer &in, dlex::Reg_def &def, std::ostream &err){
	using namespace dfa_base_str;
	using namespace dfa_base_loc;
	using namespace automata;
	int err_num=0;
	_start_state = 0;
	start_tab = entity_tab = suffix_tab=0;
	try {
		dfa_base_str::Dfa_tree &trees = build_dfa_tree(in, def, err);
		_start_line = trees.start_line;
		if( trees.start ) {		// for start tree
			dfa_base_str::Fol_val &fols = cal_fol(*trees.start);
			start_tab = &build_dfa_tab(start_acc_state, fols, trees.start->char_set, trees.start->tree->first());
			delete &fols;			// delete follow value
			delete trees.start;
			trees.start=0;
		}
		if( trees.entity ) {		// for entity tree
			dfa_base_str::Fol_val &fols = cal_fol(*trees.entity);
			entity_tab = &build_dfa_tab(entity_acc_state, fols, trees.entity->char_set, trees.entity->tree->first());
			delete &fols;
			delete trees.entity;
			trees.entity=0;
		}
		if( trees.suffix ) {
			Fol_val &fols = cal_fol(*trees.suffix);
			suffix_tab = &build_dfa_tab(suffix_acc_state, fols, trees.suffix->char_set, trees.suffix->tree->first());
			delete &fols;
			delete trees.suffix;
			trees.suffix=0;
		}
		delete &trees;			// delete three trees
	} catch(Dfa_base::Err_input) {
		err_num = 1;
	} catch(Dfa_base::Err_reg ) {
		err_num = 2;
	} catch(...) {
		err_num = 3;
	}
	if( err_num ) {
		if( start_tab ) { delete start_tab; start_tab=0; }
		if( entity_tab ) { delete entity_tab; entity_tab=0; }
		if( suffix_tab ) { delete suffix_tab; suffix_tab=0; }
		if(err_num==1||err_num==3) throw Err_input();
		else if( err_num==2) throw Err_reg();
	}	
}
//			enum Dfa_type {Start_dfa, Suffix_dfa, Normal_dfa, Start_suffix_dfa };
Dfa_base::Dfa_type Dfa_base::type() {
	Dfa_type t;
	if( start_tab ) {
		t = Start_dfa;
		if( suffix_tab )
			t = Start_suffix_dfa;
	} else if(suffix_tab) {
		t = Suffix_dfa;			// it can't be start dfa
	} else
		t = Normal_dfa;
	return t;
}
// return the next state
Dfa_base::State_type Dfa_base::start(int i, char c) {
	if( !start_tab )
		throw Dfa_base::Out_of_range();
	try {
		return start_tab->get(i, c);
	} catch(...) {
		throw Out_of_range();
	}
}
Dfa_base::State_type Dfa_base::entity(int i, char c){
	try {
		return entity_tab->get(i, c);
	} catch(...) {
		throw Out_of_range();
	}
}
Dfa_base::State_type Dfa_base::suffix(int i, char c) {
	if( !suffix_tab )
		throw Out_of_range();
	try {
		return suffix_tab->get(i, c);
	} catch(...) {
		throw Out_of_range();
	}
}
void Dfa_base::display(std::ostream &out) {
	if( start_tab ) {
		out << "The start tree.\n";
		start_tab->write(out);
		out << "Accepting states: \n" << start_acc_state << std::endl;
	}
	if( entity_tab ) {
		out << "The entity tree.\n";
		entity_tab->write(out);
		out << "Accepting states: \n" << entity_acc_state << std::endl;
	} 
	if( suffix_tab ) {
		out << "The suffix tree:\n";
		entity_tab->write(out);
		out << "Accepting states: \n" << suffix_acc_state << std::endl;
	}
}
void Dfa_base::write(std::ostream &out) {
	using namespace std;
	if( start_tab ) {
		out << start_acc_state.size() << ", ";
		for(mylib::Set<State_type>::const_iterator A=start_acc_state.begin(); A!=start_acc_state.end(); A++ )
			out << *A << ", ";
		out << endl;
		start_tab->write(out);
		out << ",\n";		// since entity must exist
	} else
		out << 0 << ",\n";		// 0 label not exist
	if( entity_tab ) {
		out << entity_acc_state.size() << ',';
		for(mylib::Set<State_type>::const_iterator A=entity_acc_state.begin(); A!=entity_acc_state.end(); A++ )
			out << *A << ", ";
		out << endl;
		entity_tab->write(out);
		out << ",\n";
	}
	if( suffix_tab ) {
		out << suffix_acc_state.size() << ',';
		for(mylib::Set<State_type>::const_iterator A=suffix_acc_state.begin(); A!=suffix_acc_state.end(); A++ )
			out << *A << ", ";
		out << endl;
		suffix_tab->write(out);
		out << endl;
	} else
		out << 0 << endl;
}
#endif
